package com.ct.websocket1;

import cn.hutool.core.util.StrUtil;
import cn.hutool.log.StaticLog;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.Timer;
import java.util.concurrent.*;

/**
 * 心跳版本的websocket通讯
 */
@Component
@ServerEndpoint("/heartBeatWebSocket/{uid}") // WebSocket 连接的 URL 格式
public class MyWebHeartBeatSocket {

    // 存储所有 WebSocket 连接 (key: 用户 ID, value: WebSocket 实例)
    private static final Map<String, MyWebHeartBeatSocket> userSessions = new ConcurrentHashMap<>();

    private Session session; // WebSocket 会话
    private String uid; // 用户 ID
    private Timer heartBeatTimer; // 心跳检测定时器
    private volatile long lastActiveTime; // 最后活跃时间 (收到消息的时间)

    //改用 全局线程池 统一管理定时任务，避免每个用户创建一个 Timer：
    private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);
    private ScheduledFuture<?> heartBeatTask;

    /**
     * WebSocket 连接建立时触发
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("uid") String uid) throws IOException {
        this.session = session;
        this.uid = uid;
        userSessions.put(uid, this);
        lastActiveTime = System.currentTimeMillis(); // 初始化心跳时间

        StaticLog.info("用户{}连接成功", uid);
        session.getBasicRemote().sendText(StrUtil.format("你好{},WebSocket 连接成功!", uid));
        // 启动心跳检测
        startHeartBeatCheck();
    }

    /**
     * 处理接收到的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        lastActiveTime = System.currentTimeMillis(); // 无论收到什么消息，都更新活跃时间

        if ("ping".equals(message)) {
            session.getBasicRemote().sendText("pong"); // 服务器回复心跳包
            StaticLog.info("收到{}的心跳包 ", uid);
        } else {
            StaticLog.info("收到用户{}的消息:{} ", uid, message);
            session.getBasicRemote().sendText("收到你的消息:" + message);
        }
    }

    /**
     * 连接关闭时触发
     */
    @OnClose
    public void onClose() {
        userSessions.remove(uid);
        StaticLog.info("用户{}断开连接", uid);
        stopHeartBeatCheck();
    }

    /**
     * 发生错误时触发
     */
    @OnError
    public void onError(Session session, Throwable error) {
        StaticLog.info("用户{}发生错误 ", uid);
        error.printStackTrace();
        stopHeartBeatCheck();
    }

    /**
     * 服务器主动向指定用户发送消息
     */
    public static void sendMessageToUser(String uid, String message) throws IOException {
        MyWebHeartBeatSocket socket = userSessions.get(uid);
        if (socket != null && socket.session.isOpen()) {
            socket.session.getBasicRemote().sendText(message);
        } else {
            StaticLog.info("用户{}不在线");
        }
    }


    /**
     * 服务器主动向所有用户发送消息
     */
    public static void sendMessageToAll(String message) {
        for (MyWebHeartBeatSocket socket : userSessions.values()) {
            try {
                socket.session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 启动心跳检测定时器
     */
    private void startHeartBeatCheck() {
   // region 耗时方案
//        heartBeatTimer = new Timer();
//        //schedule(new TimerTask(), 30000, 30000)
//        heartBeatTimer.schedule(new TimerTask() {
//            @Override
//            public void run() {
//                long now = System.currentTimeMillis();
//                if (now - lastActiveTime > 60000) { // 60 秒未收到任何消息，判定断开连接
//                    StaticLog.info("用户{}失去连接，关闭 WebSocket ", uid);
//                    try {
//                        session.close();
//                    } catch (IOException e) {
//                        e.printStackTrace();
//                    }
//                    stopHeartBeatCheck();
//                }
//            }
//        }, 30000, 30000); // 每 30 秒检查一次
        // endregion

        heartBeatTask =   scheduler.scheduleAtFixedRate(() -> {
            long now = System.currentTimeMillis();
            if (now - lastActiveTime > 60000) { // 超过 60 秒未收到消息
                StaticLog.info("用户{}失去连接，关闭 WebSocket ", uid);
                try {
                    session.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                stopHeartBeatCheck();
            }
        }, 30, 30, TimeUnit.SECONDS); // 每 30 秒检查一次
    }

    /**
     * 停止心跳检测
     */
    private void stopHeartBeatCheck() {
        if (heartBeatTimer != null) {
            heartBeatTask.cancel(false);
            heartBeatTimer = null;
        }
    }

    /**
     * 获取当前在线用户数量
     */
    public static int getOnlineCount() {
        return userSessions.size();
    }
}
